#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include <string>
#include <sstream>
#include <cassert>
#include <mutex>
#include <google/protobuf/map.h>
#include "../mqcommom/helper.hpp"
#include "../mqcommom/Log.hpp"

/*****************************************
 *  队列的设计
 *       1.队列的属性：name ,独占exclusive,durable,auto_delete,args
 *       2.队列持久化Mapper :sqlite句柄增加删除表，添加/删除队列，移除队列，恢复
 *       3.队列的管理:   mutex,Mapper,map,新增/删除 查找指定,size,clear
 *****************************************/
using namespace ns_helper;
namespace ns_rabbitmq
{
    // 管理属性方面
    class Queue
    {

    public:
        Queue(const std::string &name, bool exclusive, bool durable, bool auto_delete, const  google::protobuf::Map<std::string, std::string> &args)
            : _name(name), _exclusive(exclusive), _durable(durable), _auto_delete(auto_delete), _args(args)
        {
        }
        Queue() {}

        void SetArgs(const std::string &str)
        {
            std::vector<std::string> substr;
            StrHelper::splite(str, "&", substr);
            // 按照=划分
            for (auto &str : substr)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                _args[key] = val;
            }
        }

        std::string GetArgs()
        {
            std::string result;
            for (auto start = _args.begin(); start != _args.end(); ++start)
                result += start->first + "=" + start->second + "&";
            if(result.size())
                result.pop_back();
            return result;
        }

    public:
        std::string _name;
        bool _exclusive;
        bool _durable;
        bool _auto_delete;
        google::protobuf::Map<std::string, std::string> _args;
    };

    using MsgQueuePtr = std::shared_ptr<Queue>;
    using MsgQueMap = std::unordered_map<std::string, MsgQueuePtr>;
    class MsgQueueMapper
    {
    public:
        MsgQueueMapper(const std::string &dbfile)
            : _sqlite_helper(dbfile)
        {
            // 1.获取父路径
            std::string path = FileHelper::ParentDirctory(dbfile);
            // 2.创建路径
            FileHelper::CreateDirctory(path);
            assert(_sqlite_helper.Open());
            CreateTable();
        }
        void CreateTable()
        {
            // create table if not exists queue_table (name varchar(32) primary key,exclusive int ,durable int ,auto_delete int,args varchar(128));
            std::string sql = "create table if not exists queue_table (";
            sql += "name varchar(32) primary key,exclusive int ,durable int ,auto_delete int,args varchar(128)";
            sql += ");";
            _sqlite_helper.Exec(sql, nullptr, nullptr);
        }

        void RemoveTable()
        {
            std::string sql = "drop table if exists queue_table;";
            _sqlite_helper.Exec(sql, nullptr, nullptr);
        }

        bool Insert(const MsgQueuePtr &msgqueueptr)
        {
            std::stringstream sql;
            sql << "insert into queue_table values(";
            sql << "'" << msgqueueptr->_name << "',";
            sql << msgqueueptr->_exclusive << "," << msgqueueptr->_durable << "," << msgqueueptr->_auto_delete;
            sql << ",'" << msgqueueptr->GetArgs() << "');";
            return _sqlite_helper.Exec(sql.str(), nullptr, nullptr);
        }

        bool RevomeQueue(const std::string &name)
        {
            std::string sql = "delete from queue_table  where name ='" + name + "';";
            return _sqlite_helper.Exec(sql, nullptr, nullptr);
        }

        MsgQueMap Recovery()
        {
            MsgQueMap queue_map;
            std::string sql = "select * from queue_table;";
            _sqlite_helper.Exec(sql, RecoveryCallback, &queue_map);
            return queue_map;
        }

    private:
        static int RecoveryCallback(void *args, int numcol, char **row, char **fields)
        {
            // 1.获取args
            MsgQueMap *mq_map = static_cast<MsgQueMap *>(args);
            MsgQueuePtr msgqueueptr = std::make_shared<Queue>();
            msgqueueptr->_name = row[0];
            msgqueueptr->_exclusive = (bool)row[1];
            msgqueueptr->_durable = (bool)row[2];
            msgqueueptr->_auto_delete = (bool)row[3];
            if (row[4])
                msgqueueptr->SetArgs(row[4]);
            mq_map->insert(std::make_pair(msgqueueptr->_name, msgqueueptr));
            return 0;
        }
        SqliteHelper _sqlite_helper;
    };

    class QueueManager
    {
    public:
        using QueueManagerPtr = std::shared_ptr<QueueManager>;
        QueueManager(const std::string &dbfile)
            : _mapper(dbfile)
        {
            // 重启时，恢复数据
            _msg_queues = _mapper.Recovery();
        }

        bool DeclareQueue(const std::string &name, bool exclusive,
                          bool durable, bool auto_delete, const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _msg_queues.find(name);
            if (pos != _msg_queues.end())
            {
                // 存在机器,直接返回
                return false;
            }
            auto queue_machine = std::make_shared<Queue>(name, exclusive, durable, auto_delete, args);
            if (durable)
                _mapper.Insert(queue_machine);
            _msg_queues.insert(std::make_pair(name, queue_machine));
            return true;
        }

        void DeleteQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _msg_queues.find(name);
            if (pos == _msg_queues.end())
            {
                // 不存在机器，就直接返回
                std::cout << "没找到" << std::endl;
                return;
            }
            _msg_queues.erase(name);
            if (pos->second->_durable)
                _mapper.RevomeQueue(name);
            std::cout << "删除了" << std::endl;
        }

        // 获取指队列
        MsgQueuePtr SelectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _msg_queues.find(name);
            if (pos == _msg_queues.end())
            {
                // 不存在就返回
                return MsgQueuePtr();
            }
            return pos->second;
        }

        MsgQueMap AllQueues()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues;
        }

        bool IsExistsQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto pos = _msg_queues.find(name);
            if (pos == _msg_queues.end())
                return false;
            return true;
        }
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _msg_queues.clear();
        }
        ssize_t Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues.size();
        }

    private:
        std::mutex _mutex;
        MsgQueueMapper _mapper;
        MsgQueMap _msg_queues;
    };
}